#include "SurfManager.h"

SurfaceManager::SurfaceManager( vPlanet *_planet ) : TileManager( _planet ) {

	maxlvl = min(	*(int*)gc->GetConfigParam( CFGPRM_SURFACEMAXLEVEL ),				//global
					*(int*)oapiGetObjectParam( obj, OBJPRM_PLANET_SURFACEMAXLEVEL ) );	//planet-specific
	maxbaselvl = min( 8, maxlvl );

	pcdir = _V( 1.0, 0.0, 0.0 );
	lightfac = (float)(*(double*)gc->GetConfigParam( CFGPRM_SURFACELIGHTBRT ));
	spec_base = 0.95f;
//	atmc = oapiGetPlanetAtmConstants( obj );

	tiledesc = new TILEDESC[patchidx[maxbaselvl]];
	memset( tiledesc, 0, sizeof(TILEDESC)*patchidx[maxbaselvl] );
//***
	char fname[256], cpath[256];
	strcpy_s( fname, 256, objname );
	strcat_s( fname, 256, "_tile.tex" );
	if( gc->TexturePath( fname, cpath ) ) {
		UINT slen = strlen( cpath )+1;
		Planet_tile_fpath = new char [slen];
		strcpy_s( Planet_tile_fpath, slen, cpath );
	}

	strcpy_s( fname, 256, objname );
	strcat_s( fname, 256, "_tile_lmask.tex" );
	if( gc->TexturePath( fname, cpath ) ) {
		UINT slen = strlen( cpath )+1;
		Planet_tile_lmask_fpath = new char [slen];
		strcpy_s( Planet_tile_lmask_fpath, slen, cpath );
	}

	sprintf( cpath, "Loading planet textures: %s", objname );
	gc->ProgressString( cpath, 4 );

	LoadSpecularMaskData();
	LoadTileData();
	LoadTextures();
	LoadSpecularMasks();

	Shader_prev = 0;	
}

SurfaceManager::~SurfaceManager() {
	delete [ ] tiledesc;
}

void SurfaceManager::SetMicrotexture( const char *fname ) {
	TileManager::SetMicrotexture( fname );
	spec_base = (microtex ? 1.05f : 0.95f); // increase specular intensity to compensate for "ripple" losses
}

void SurfaceManager::Render( /*D3DXMATRIX &wmat, double scale, int level, double viewap, bool bfog*/ ) {
	//SpecularColor() moved to InitRenderTile()
	TileManager::Render( /*wmat, scale, level, viewap, bfog*/ );
}

void SurfaceManager::RenderSimple( int lvl, int npatch, TILEDESC *tile, D3DXMATRIX *mWorld ) {
/*	Renders L1-L4 sphere for lower resolutions.
	*/
	const UINT TileVertexStride = 40, VBOffset = 0;

	InitRenderTile();

	VSCB_Planet_1.WVP = *mWorld* *SC->GetVP();// gc->GetScene()->ViewProj;//ViewProj!
	VSCB_Planet_1.W = *mWorld;
	VSCB_Planet_1.TexOff.x = 1.0f;
	VSCB_Planet_1.TexOff.y = 0.0f;
	VSCB_Planet_1.TexOff.z = 1.0f;
	VSCB_Planet_1.TexOff.w = 0.0f;
	dCtx->UpdateSubresource( cb_VS_Planet[1], 0, NULL, &VSCB_Planet_1, 0, 0 );
	
	for( DWORD idx = 0; idx < npatch; idx++ ) {
		TILEMESH &mesh = TPL[lvl][idx];

	//	gc->GetStats()->Vertices += mesh.nVtx;
	//	gc->GetStats()->Tiles[level]++;
	//	gc->GetStats()->Draw++;

		if( ((tile[idx].flag & 3 ) == 2 ) )			PSCB_Planet_1.SpecMode = 1;
		else if( ((tile[idx].flag & 3 ) == 3 ) )	PSCB_Planet_1.SpecMode = 2;
		else										PSCB_Planet_1.SpecMode = 0;

		if( !tile[idx].ltex )	PSCB_Planet_1.LTex = 0;
		else					PSCB_Planet_1.LTex = 1;

		dCtx->UpdateSubresource( cb_PS_Planet[1], 0, NULL, &PSCB_Planet_1, 0, 0 );

		DWORD Shader = !tile->ltex ? 0 : ( microtex ? 2 : 1 );
		if( Shader != Shader_prev )
			dCtx->PSSetShader( PS_Planet[Shader], NULL, NULL );
		Shader_prev = Shader;

		dCtx->PSSetShaderResources( 0, 1, &tile[idx].tex );
		dCtx->PSSetShaderResources( 1, 1, &tile[idx].ltex );

		dCtx->IASetVertexBuffers( 0, 1, &mesh.VB, &TileVertexStride, &VBOffset );
		dCtx->IASetIndexBuffer( mesh.IB, DXGI_FORMAT_R16_UINT, 0 );

		dCtx->DrawIndexed( mesh.nidx, 0, 0 );
	}
}

void SurfaceManager::RenderTile( int hemisphere, int lvl, int ilat, int nlat, int ilng, int nlng, /*double sdist,*/ TILEDESC *tile,
		const TEXCRDRANGE &range, ID3D11ShaderResourceView *tex, ID3D11ShaderResourceView *ltex, DWORD flag )
{
/*	Renders one of L5-L14 tiles
	*/
	const UINT TileVertexStride = 40, VBOffset = 0;

	TILEMESH &mesh = TPL[lvl][ilat];

	VSCB_Planet_1.WVP = mWorld * *SC->GetVP();//ViewProj!
	VSCB_Planet_1.W = mWorld;
	if( range.tumin == 0 && range.tumax == 1 ) {
		VSCB_Planet_1.TexOff.x = 1.0f;
		VSCB_Planet_1.TexOff.y = 0.0f;
		VSCB_Planet_1.TexOff.z = 1.0f;
		VSCB_Planet_1.TexOff.w = 0.0f;
	}
	else {
		VSCB_Planet_1.TexOff.x = range.tumax - range.tumin;
		VSCB_Planet_1.TexOff.y = range.tumin;
		VSCB_Planet_1.TexOff.z = range.tvmax - range.tvmin;
		VSCB_Planet_1.TexOff.w = range.tvmin;
	}
	dCtx->UpdateSubresource( cb_VS_Planet[1], 0, NULL, &VSCB_Planet_1, 0, 0 );

	if( ((flag & 3 ) == 2 ) )		PSCB_Planet_1.SpecMode = 1;
	else if( ((flag & 3 ) == 3 ) )	PSCB_Planet_1.SpecMode = 2;
	else							PSCB_Planet_1.SpecMode = 0;
	if( !ltex )		PSCB_Planet_1.LTex = 0;
	else			PSCB_Planet_1.LTex = 1;
	
	dCtx->PSSetShaderResources( 0, 1, &tex );
	if( ltex )	
		dCtx->PSSetShaderResources( 1, 1, &ltex );
	dCtx->UpdateSubresource( cb_PS_Planet[1], 0, NULL, &PSCB_Planet_1, 0, 0 );

	DWORD Shader = !ltex ? 0 : ( microtex ? 2 : 1 );
	if( Shader != Shader_prev )
		dCtx->PSSetShader( PS_Planet[Shader], NULL, NULL );
	Shader_prev = Shader;

	dCtx->IASetVertexBuffers( 0, 1, &mesh.VB, &TileVertexStride, &VBOffset );
	dCtx->IASetIndexBuffer( mesh.IB, DXGI_FORMAT_R16_UINT, 0 );

	dCtx->DrawIndexed( mesh.nidx, 0, 0 );
}

void SurfaceManager::InitRenderTile() {
	dCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	dCtx->IASetInputLayout( IL_TileVertex );
	dCtx->VSSetShader( VS_Planet, NULL, NULL );
	dCtx->VSSetConstantBuffers( 0, 2, cb_VS_Planet );
	dCtx->PSSetConstantBuffers( 0, 2, cb_PS_Planet );
	dCtx->PSSetSamplers( 0, 1, &SS_Planet );
	dCtx->OMSetBlendState( BS_NoBlend, D3DXCOLOR( 1, 1, 1, 1 ), 0xFFFFFFFF );
	dCtx->OMSetDepthStencilState( DSS_Write0_Test0, 0 );
	dCtx->RSSetState( RS_Back_Solid );

	ATM_FOG_PARAMS *AP = planet->GetAtmParams();
	VSCB_Planet_0.Ambient0 = AP->Ambient0;
	VSCB_Planet_0.Dispersion = AP->Dispersion;
	VSCB_Planet_0.FogColor = AP->FogColor;
	VSCB_Planet_0.FogDensity = AP->FogDensity;
	VSCB_Planet_0.GlobalAmb = AP->GlobalAmb;
	VSCB_Planet_0.HazeMode = AP->HazeMode;
	VSCB_Planet_0.SunAppRad = AP->SunAppRad;
	VSCB_Planet_0.SunDir = AP->SunDir;

	D3DXCOLOR WaterSpec;
	SpecularColor( &WaterSpec );
	WaterSpec.a = (microtex ? 30.0f : 35.0f );
	VSCB_Planet_0.WMat_spower = WaterSpec.a;	//WMat_spower
	dCtx->UpdateSubresource( cb_VS_Planet[0], 0, NULL, &VSCB_Planet_0, 0, 0 );

	PSCB_Planet_0.cWaterSpec = WaterSpec;
	D3DXVECTOR3 cAmbient = planet->obj == SC->GetProxyBody() ? D3DXVECTOR3( 0.0f, 0.0f, 0.0f ) : *SC->GetAmbientColor();
	PSCB_Planet_0.cAmbient = D3DXCOLOR( cAmbient.x, cAmbient.y, cAmbient.z, 1.0f );
	dCtx->UpdateSubresource( cb_PS_Planet[0], 0, NULL, &PSCB_Planet_0, 0, 0 );

	if( microtex ) {
		dCtx->PSSetShaderResources( 2, 1, &microtex );
		dCtx->PSSetSamplers( 1, 1, &SS_Planet_micro );
		PSCB_Planet_1.Mix = 1.0f;
	}
	else
		PSCB_Planet_1.Mix = 0.0f;

	Shader_prev = 10;
}

void SurfaceManager::EndRenderTile() {
/*	Not needed	*/
}